package com.test.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.test.entity.Const;
import com.test.entity.dto.Account;
import com.test.service.AccountService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class JwtUtils {
    @Value("${spring.security.jwt.key}")
    String key;
    @Value("${spring.security.jwt.time}")
    int expire;
    @Resource
    StringRedisTemplate template;
    @Resource
    AccountService service;

    public Boolean inValidated(String header){
        String token = this.convertToken(header);
        if(token == null) return false;
        //确定算法
        Algorithm algorithm = Algorithm.HMAC256(key);
        //确定验证器
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        try{
            DecodedJWT jwt = jwtVerifier.verify(token);
            //获取令牌到期时间
            String id = jwt.getId();
            Date date = jwt.getExpiresAt();
            return deleteToken(id,date);

        }
        catch (JWTVerificationException e){
            return  null;
        }
    }
    public Boolean deleteToken(String id,Date date){
        if(isInvalidated(id)){
            return false;
        }
        Date now = new Date();
        long expire = Math.max(0,date.getTime()-now.getTime());
        template.opsForValue().set(Const.JWT_BLACK_LIST +id,"",expire, TimeUnit.MILLISECONDS);
        return true;

    }
    public Boolean isInvalidated(String id){
        return template.hasKey(Const.JWT_BLACK_LIST+id);
    }

    /**
     * 将解码后的JWT转换为用户详情信息
     * 此方法主要用于将JWT中携带的用户信息转换为应用中的用户详情对象
     * 它读取JWT中的claims（声明），并使用这些信息来构建一个用户对象
     * 注意：此方法不验证JWT的合法性和时效性，仅负责解析和转换信息
     *
     * @param jwt 解码后的JWT对象，包含用户相关信息
     * @return UserDetails对象，代表应用中的用户详情
     */
    public UserDetails toUser(DecodedJWT jwt){
        // 获取JWT中的所有声明，这些声明包含了用户信息
        Map<String, Claim> claims = jwt.getClaims();
        Account account = service.findByUsername(claims.get("name").asString());
        // 使用JWT中的信息构建用户对象
        return User
                .withUsername(claims.get("name").asString())
                .password(account.getPassword())

                // 从JWT中提取用户的权限信息，并将其设置到用户对象中
                .authorities((claims.get("authorities")).asArray(String.class))
                .build();

    }
    public String convertToken(String token){
        if(token != null && token.startsWith("Bearer ")){
             return token.substring(7);

        }
        return null;
    }
    /**
     * 将HTTP请求头中的token令牌转换并解析为实体类DecodedJWT
     * 此方法主要用于验证和解析JWT令牌，以确保令牌的有效性
     *
     * @param header HTTP请求头中的令牌字符串
     * @return 解析后的DecodedJWT对象，如果令牌无效或已过期，则返回null
     */
    public DecodedJWT resolve(String header){

        // 将header中的令牌字符串转换为可解析的格式
        String token = this.convertToken(header);
        // 如果转换后的token为空，则直接返回null
        if(token == null) return null;

        // 确定算法，使用HMAC256对称加密算法，key为密钥
        Algorithm algorithm = Algorithm.HMAC256(key);

        // 确定验证器，用于验证JWT令牌
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();

        try{
            // 使用验证器验证并解析令牌
            DecodedJWT jwt = jwtVerifier.verify(token);

            // 检查JWT是否已被废除
            if(isInvalidated(jwt.getId())){
                return null;
            }

            // 获取令牌到期时间
            Date expiresAt = jwt.getExpiresAt();

            // 验证令牌是否过期
            return new Date().after(expiresAt) ? null : jwt;

        }
        catch (JWTVerificationException e){
            // 如果验证异常，则返回null
            return  null;
        }
    }
    /**
     * 创建一个JSON Web Token (JWT)
     *
     * @param user 用户对象，用于获取用户权限信息
     * @param id 用户ID
     * @param name 用户名称
     * @return 返回生成的JWT字符串
     *
     * 此方法用于生成一个包含用户信息的JWT，包括用户ID、用户名和权限信息，
     * 并设置令牌的过期时间和签发时间使用HMAC256算法对JWT进行签名
     */
    public String createJwt(User user, int id, String name){
        // 创建HMAC256算法实例，用于签名JWT
        Algorithm algorithm = Algorithm.HMAC256(key);

        // 开始创建JWT
        return JWT.create()
                // 设置JWT的唯一标识符
                .withJWTId(UUID.randomUUID().toString())
                // 设置用户ID
                .withClaim("id",id)
                // 设置用户名
                .withClaim("name",name)
                // 设置用户权限信息，通过流处理用户权限集合并转换为字符串列表
                .withClaim("authorities",user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
                // 设置JWT的过期时间
                .withExpiresAt(expireTime())
                // 设置JWT的签发时间
                .withIssuedAt(new Date())
                // 使用HMAC256算法对JWT进行签名并返回签名后的JWT字符串
                .sign(algorithm);
    }
    public Date expireTime(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR,expire*24);
        return  calendar.getTime();
    }
}
